/**
 * Copyright 2000 self.com.au
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. (http://www.apache.org/licenses/LICENSE-2.0)
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed 
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for 
 * the specific language governing permissions and limitations under the License.
 *
 * <dhamma-message src="Atisha (11th century Tibetan Buddhist master)">
 * 	The greatest achievement is selflessness. The greatest worth is self-mastery.
 * 	The greatest quality is seeking to serve others. The greatest precept is continual awareness.
 * 	The greatest medicine is the emptiness of everything. The greatest action is not conforming with the worlds ways.
 * 	The greatest magic is transmuting the passions. The greatest generosity is non-attachment.
 * 	The greatest goodness is a peaceful mind. The greatest patience is humility.
 * 	The greatest effort is not concerned with results. The greatest meditation is a mind that lets go.
 * 	The greatest wisdom is seeing through appearances. 
 * </dhamma-message>
 *
 * @author Ashin Wimalajeewa
 */
package self.amigo.elem;

import java.io.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;

import org.w3c.dom.*;

import self.gee.*;
import self.text.*;
import self.xml.*;

public abstract class ALinkableGraphic implements ILinkableGraphic, Serializable {
  final static public String SHAKERS_PROP = "Shakers";

  private int refId;
  protected IGraphicElement delegate;
  private ArrayList shakers = new ArrayList();

  public ALinkableGraphic() {
    refId = hashCode();
  }

  public void       setLayer( IDiagramLayer layerToDrawOn, boolean add ) {
    if ( add )
      layerToDrawOn.addElement( this );
    delegate.setLayer( layerToDrawOn, false );
  }

  protected void setDelegate( IGraphicElement toDecorate ) {
    delegate = toDecorate;
  }

  // ILinkableGraphic support
  public void attachElement( ILinkGraphic shaker ) {
    if ( shakers.indexOf(shaker) == -1 )
      shakers.add( shaker );
  }

  public void detachElement( ILinkGraphic shaker ) {
    shakers.remove( shaker );
  }

  public void getAttachments( java.util.List store ) {
    store.addAll( shakers );
  }

  // IGraphicElement support
  public int        getReferenceId() {
    return refId;
  }

  public void       paint( Graphics surface ) {
    delegate.paint( surface );
  }

  public void       setLocation( int x, int y ) {
    delegate.setLocation( x, y );
    fireLinkerHasChangedEvent( ILinkableGraphic.MOVED_EVENT );
  }

  public void       move( Dimension moveBy, MouseEvent e, int dragState ) {
    delegate.move( moveBy, e, dragState );
    fireLinkerHasChangedEvent( ILinkableGraphic.MOVED_EVENT );
  }

  public void       resize( int x, int y, Point[] handle, MouseEvent e, int dragState ) {
    delegate.resize( x, y, handle, e, dragState );
    fireLinkerHasChangedEvent( ILinkableGraphic.RESIZED_EVENT );
  }

  public void       remove() {
    delegate.getLayer().removeElement( this );
    fireLinkerHasChangedEvent( ILinkableGraphic.REMOVED_EVENT );
    delegate.remove();
  }

  public boolean    getLineIntersectionToCentre( int xFrom, int yFrom, int[] xyPoints ) {
    return delegate.getLineIntersectionToCentre( xFrom, yFrom, xyPoints );
  }

  public void       getHandlePoints( java.util.List store ) {
    delegate.getHandlePoints( store );
  }

  public boolean    contains( Point within ) {
    return delegate.contains( within );
  }

  public boolean    isWithin( Rectangle within ) {
    return delegate.isWithin( within );
  }

  public boolean    areDependentsListed( java.util.List toCheck ) {
    return delegate.areDependentsListed( toCheck );
  }

  public Rectangle getBounds() {
    return delegate.getBounds();
  }

  public Rectangle  getOverallBounds() {
    return delegate.getOverallBounds();
  }

  public IDiagramLayer getLayer() {
    return delegate.getLayer();
  }

  // IEditableElement support
  public void       getProperties( Map store ) {
    delegate.getProperties( store );
  }

  public void       setProperties( Map data ) {
    delegate.setProperties( data );
    fireLinkerHasChangedEvent( ILinkableGraphic.PROPERTY_CHANGED_EVENT );
  }

  // IPersistentElement support
  public void readFrom( Node self, HashMap idObjLookUp ) throws DOMException {
    ArrayList list = new ArrayList();
    Node shakersElem = DomUtils.getChildElementNode( self, SHAKERS_PROP );
    String links = DomUtils.getElementText( shakersElem );
    if ( links != null ) {
      CommaDelimitedUtils.intSeriesToList( links, list );
      int max = list.size();
      for ( int cntr = 0; cntr < max; cntr++ ) {
        String id = list.get( cntr ).toString();
        Object shaker = idObjLookUp.get( id );
        if ( shaker == null )
          continue;
        shakers.add( shaker );
      }
    }
    delegate.readFrom( self, idObjLookUp );
  }

  public void writeTo( Document doc, Element self, HashMap objIdLookup ) throws DOMException {
    ArrayList list = new ArrayList();
    int max = shakers.size();
    for ( int cntr = 0; cntr < max; cntr++ ) {
      String id = (String) objIdLookup.get( shakers.get(cntr) );
      if ( id == null )
        continue;
      list.add( id );
    }
    Element shakersElem = doc.createElement( SHAKERS_PROP );
    self.appendChild( shakersElem );
    String links = CommaDelimitedUtils.objectsToSeries( list );
    DomUtils.setElementText( shakersElem, links );
    delegate.writeTo( doc, self, objIdLookup );
  }

  public String toString() {
    StringBuffer shkrs = new StringBuffer();
    int max = shakers.size();
    shkrs.append( "[shakers:" );
    for ( int cntr = 0; cntr < max; cntr++ ) {
      Object shkr = shakers.get( cntr );
      if ( cntr > 0 )
        shkrs.append( ", " );
      shkrs.append( shkr.hashCode() );
    }
    shkrs.append( "]" );
    shkrs.append( delegate.toString() );
    return "[" + this.getClass().getName() + "@" + hashCode() +"]" + shkrs.toString();
  }

  protected void fireLinkerHasChangedEvent( int event ) {
    int max = shakers.size();
    ArrayList tmp = new ArrayList( max );
    tmp.addAll( shakers );
    for ( int cntr = 0; cntr < max; cntr++ ) {
      ILinkGraphic elem = (ILinkGraphic) tmp.get( cntr );
      elem.linkerHasChanged( this, event );
    }
  }
}
